package pe.edu.unmsm.fisi.ceups.modelo.entidad;

import java.util.Vector;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
/**
 *
 * @author Liz Aurora
 */
public class Algoritmograsp {

    int MD[][];
    int ML[][];
    Vector<int[][]> Mlab;
    int Mlab1[][];
    int Mlab2[][];
    int nhoras = 6;

    public Algoritmograsp() {
        
        //Matriz de horarios de docente (14 filas x 7 columnas)
        
        MD = new int[][]{
                    {0, 1, 1, 0, 0, 0, 0},
                    {0, 0, 0, 0, 0, 0, 0},
                    {0, 0, 0, 0, 0, 0, 0},
                    {0, 1, 1, 0, 0, 0, 0},
                    {0, 1, 1, 0, 0, 0, 0},
                    {0, 1, 1, 0, 0, 0, 0},
                    {0, 0, 0, 0, 0, 0, 0},
                    {0, 0, 0, 0, 0, 0, 0},
                    {0, 0, 0, 0, 0, 0, 0},
                    {0, 1, 1, 0, 0, 1, 0},
                    {0, 1, 1, 0, 0, 1, 0},
                    {0, 0, 1, 0, 0, 0, 0},
                    {0, 1, 1, 0, 0, 0, 0},
                    {0, 1, 1, 0, 1, 1, 0}
                };


        //Matriz de horarios del laboratorio 1 (14 filas x 7 columnas)
        Mlab1 = new int[][]{
                    {0, 1, 1, 0, 1, 0, 0},
                    {0, 0, 0, 0, 1, 0, 0},
                    {0, 0, 0, 1, 1, 0, 0},
                    {0, 1, 1, 0, 1, 0, 0},
                    {0, 1, 1, 1, 0, 0, 1},
                    {0, 1, 1, 1, 0, 0, 1},
                    {0, 0, 0, 1, 0, 0, 1},
                    {0, 0, 0, 0, 0, 0, 1},
                    {0, 0, 0, 1, 0, 0, 1},
                    {0, 1, 1, 0, 0, 1, 1},
                    {0, 1, 1, 0, 1, 1, 1},
                    {0, 0, 1, 0, 1, 1, 0},
                    {0, 1, 1, 0, 1, 0, 1},
                    {0, 1, 1, 0, 1, 1, 1}
                };
        //Matriz de horarios de laboratorio 2(14 filas x 7 columnas)
        Mlab2 = new int[][]{
                    {0, 1, 1, 0, 1, 0, 0},
                    {0, 0, 0, 0, 0, 0, 0},
                    {0, 0, 0, 1, 0, 0, 0},
                    {0, 1, 1, 0, 0, 0, 0},
                    {0, 1, 1, 1, 0, 0, 1},
                    {0, 1, 0, 1, 0, 0, 1},
                    {0, 0, 0, 0, 0, 0, 1},
                    {0, 0, 0, 0, 0, 0, 1},
                    {0, 1, 0, 1, 0, 0, 1},
                    {0, 1, 0, 0, 0, 0, 0},
                    {0, 1, 0, 0, 1, 0, 1},
                    {0, 0, 1, 0, 1, 1, 0},
                    {0, 1, 1, 0, 1, 0, 1},
                    {0, 1, 1, 0, 1, 0, 1}
                };



        Mlab = new Vector<int[][]>();
        
        /*Para la prueba solo añadimos al vector de matrices 
        de laboratorio 2 elementos*/
        
        Mlab.add(Mlab1);
        Mlab.add(Mlab2);
    }

    public Vector<int[][]> genera_matriz_interseccion(int Md[][], int mdc, int mdf, Vector<int[][]> Ml) {
   
     /*
     Este metodo recibe como parametros una matriz de horarios de docentes, sus indices (columnas, filas)
     y el vector de matrices de laboratorios.
     Este metodo devuelve un vector de matrices de las intersecciones.     
     
     */

        Vector<int[][]> Mi = new Vector<int[][]>();

        for (int m = 0; m < Ml.size(); m++) {
            int Ma[][] = new int[mdf][mdc];
            for (int i = 0; i < mdf; i++) {
                for (int j = 0; j < mdc; j++) {

                    if (Md[i][j] == Ml.get(m)[i][j]) {

                        if (Md[i][j] == 1) {
                            Ma[i][j] = 1;
                        } else {
                            Ma[i][j] = 0;
                        }


                    } else {
                        Ma[i][j] = 0;
                    }
                }
            }

            Mi.add(Ma);

        }

        return Mi;

    }

    public Vector<Integer> vhoras(int nhoras) {
    /*
     Este metodo recibe el numero de horas totales por semana si es que no se colocan
     algunas especificaciones para personalizar la generación del horario.
     Este metodo nos devuelve un vector de enteros , que son el numero de horas por sesion.
     
     */
        Vector<Integer> vh = new Vector<Integer>();


        if (nhoras % 2 == 0) {
            for (int v = 0; v < (nhoras / 2); v++) {
                vh.add(2);
            }
        } else {
            vh.add(3);
            for (int v = 0; v < (nhoras / 2) - 1; v++) {
                vh.add(2);
            }
        }

        return vh;
    }

    public Vector<int[]> generar_vindices(Vector<Integer> vh, Vector<int[][]> mi, int mdc, int mdf) {

        /*
         Este metodo recibe como parametros el Vector de horas(horas por sesion), el vector de matrices
         con las intersecciones, el numero de columnas y filas.
         Este metodo nos devuelve un Vector de vector de enteros, en la cual se almacenan:
         * 1. el indice de la fila
         * 2. el indice de la columna
         * 3. el indice de la matriz de intersecciones evaluada
         * 4. el numero de horas evaluada.
         * 5. el desperdicio de horas.
         Lo que hace este metodo es buscar por cada elemento del vector de horas, en el vector de matrices horas
         consecutivas por dia que sean mayores o iguales que las  del elemento del vector de horas.
         * 
         * 
         El metodo nos devuelve un vector de de array de enteros, en los que se guardan los indices antes
         mencionados.
         */
        
        
        int c;
        int[] vindices;
        Vector<int[]> vdindices = new Vector<int[]>();

        for (int v = 0; v < vh.size(); v++) {

            c = 0;

            for (int m = 0; m < mi.size(); m++) {

                for (int i = 0; i < mdc; i++) {
                    c = 0;
                    for (int j = 0; j < mdf; j++) {

                        if (mi.get(m)[j][i] == 1) {

                            boolean sw = true;
                            boolean sw1 = true;

                            int p = 0;
                            int p1 = 0;
                            int pt = 0;

                            /*Ascendente*/

                            while (sw) {
                                if (mi.get(m)[j + p][i] == 1) {
                                    p++;

                                } else {
                                    sw = false;
                                }

                                if (j + p >= mdf) {
                                    sw = false;
                                }

                            }

                            /*Descendente*/

                            while (sw1) {
                                if (mi.get(m)[j - p1][i] == 1) {
                                    p1++;

                                } else {
                                    sw1 = false;
                                }

                                if (j - p1 < 0) {
                                    sw1 = false;
                                }

                            }

                            pt = p1 + p - 1;


                            if (p >= vh.get(v)) {
                                vindices = new int[5];
                                vindices[0] = j;
                                vindices[1] = i;
                                vindices[2] = m;
                                vindices[3] = vh.get(v);
                                vindices[4] = pt - vh.get(v);
                                vdindices.add(vindices);

                            }

                        }
                    }

                }

            }

        }

        return vdindices;

    }

    public  Vector<int []> busca(double relax, Vector<int []> eval, int tam){
        
       Vector<int []> zeval=new Vector();
        
        
       int min = eval.get(0)[4];
       int max = eval.get(0)[4];
       
        for (int m = 0; m < eval.size(); m++) {

            if (eval.get(m)[4] < min && eval.get(m)[3] == tam) {
                min = eval.get(m)[4];
            }
             if (eval.get(m)[4] > max && eval.get(m)[3] == tam) {
                max = eval.get(m)[4];
            }

        }
       
       for(int c=0;c<eval.size();c++)
       {
       
      //zeval.add(eval.get(c)[4]
           
           if((max-relax*(max-min))<= eval.get(c)[4] && eval.get(c)[4]<=max){
           
               zeval.addElement(eval.get(c));
           
           }
       
       
       }
       
       return zeval;
                
    
    
    }
    
    public Vector<int[]> generar_posibles(Vector<int[]> vi, int tam) {
        /*
         Este metodo recibe como parametros el vector de array de indices buscados,
         y el numero de horas buscado (es decir algun elemento del vector de horas)
         Este metodo nos devuelve un vector de indices con elementos que cumplan con
         el desperdicio de horas minimo.
         * 
         Es decir de todos los elementos se busca un minimo y con ese se compara.
         
         */
        
        Vector<int[]> pos = new Vector();


        int min = vi.get(0)[4];

        for (int m = 0; m < vi.size(); m++) {

            if (vi.get(m)[4] < min && vi.get(m)[3] == tam) {
                min = vi.get(m)[4];
            }

        }

        for (int p = 0; p < vi.size(); p++) {

            if (vi.get(p)[4] == min && vi.get(p)[3] == tam) {
                pos.add(vi.get(p));

            }

        }

        return pos;

    }

    public Vector<int[]> generar_horarios(Vector<int[]> vi, int mdc, int mdf, Vector<Integer> vhr) {
    /*
     Este metodo es el que funciona coomo el algoritmo grasp, recibe como parametros un vector de array de enteros
     recibe tambien el numero de columnas y filas, y el vector de horas
     * 
     Nota: para posteriores usos el vector de horas puede ser reemplazado por un vector que contenga las
     horas que queramos.
     * 
     El metodo nos devuelve el vector con las soluciones de posibles horarios, cada vez que se le llama genera uno
     nuevo por q es random, se le asigna un numero dterminado de recorridos q va a hacer(100) hasta encontrar la solución.
     
     La solución trata de no repetirse ya q se excluye del vector aquellos dias que ya fueron asignados
     
     
     */
        int ncorridas=100;
        double prelajación=0.5;
       
        Vector<int[]> re = new Vector();
        Vector<int[]> rcl = new Vector();

        for (int c = 0; c < vhr.size(); c++) {
            Vector<int[]> pos = new Vector();
            pos = this.generar_posibles(vi, vhr.get(c));
            
            rcl=this.busca(prelajación, pos, vhr.get(c));
            
            boolean sw = false;

            for (int w = 0; w < ncorridas && !sw; w++) {
                sw = true;

                int r = (int) (Math.random() * rcl.size());

                for (int u = 0; u < re.size(); u++) {
                    if (re.get(u)[1] == rcl.get(r)[1]) {
                        sw = false;
                    }
                }
                if (sw) {
                    re.add(pos.get(r));
                }

                 //System.out.println("w: "+w+" random: "+r);
                
            }
            
        }
       
           System.out.println("re"+re.size()+" vh: "+vhr.size());
        return re;
    }

    public static void main(String a[]) {
        Algoritmograsp am = new Algoritmograsp();
        // am.vhoras(7);
        Vector<int[][]> hrs = am.genera_matriz_interseccion(am.MD, 7, 14, am.Mlab);

        for (int i = 0; i < hrs.size(); i++) {
            String r = "\n\n" + i;
            System.out.println(r);
            for (int k = 0; k < 14; k++) {

                String h = "";
                for (int j = 0; j < 7; j++) {
                    h = h + "  " + hrs.get(i)[k][j];

                }

                System.out.println(h);
            }


        }
        Vector<Integer> f = am.vhoras(7);

        String t = "";

        for (int i = 0; i < f.size(); i++) {
            t = t + "  " + f.get(i);

        }
        
        System.out.println("vector de horas generado");
        System.out.println(t);



        Vector<int[]> res = am.generar_vindices(f, hrs, 7, 14);




        for (int i = 0; i < res.size(); i++) {
            String r = "";
            for (int j = 0; j < res.get(i).length; j++) {
                r = r + "  " + res.get(i)[j];

            }
            System.out.println("vector de indices:");
            
            System.out.println("#indice de hora - dia - lab - tipohora - desperdicio");
        
            System.out.println(r);
        }

        Vector<int[]> sol = am.generar_horarios(res, 7, 14, f);
         System.out.println("Solucion:\n");
        
        
        for (int i = 0; i < sol.size(); i++) {
            String r = "";
            for (int j = 0; j < sol.get(i).length; j++) {
                r = r + "  " + sol.get(i)[j];

            }
            System.out.println("#indice de hora - dia - lab - tipohora - desperdicio");    
            System.out.println(r);
        }


    }
}
